// (c) Copyright 2013-2014 Stephen Gold <sgold@sonic.net>
// Distributed under the terms of the GNU General Public License

/*
 This file is part of the Bats Game.

 The Bats Game is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by the
 Free Software Foundation, either version 3 of the License, or (at your
 option) any later version.

 The Bats Game is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 for more details.

 You should have received a copy of the GNU General Public License
 along with the Bats Game.  If not, see <http://www.gnu.org/licenses/>.
 */
package bats.unit;

import bats.scene.SceneNode;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import java.util.ArrayList;
import java.util.logging.Logger;
import jme3utilities.math.MyVector3f;

/**
 * A list of potential targets for attack.
 *
 * @author Stephen Gold <sgold@sonic.net>
 */
public class Targets {
    // *************************************************************************
    // constants

    /**
     * message logger for this class
     */
    final private static Logger logger =
            Logger.getLogger(Targets.class.getName());
    // *************************************************************************
    // fields
    /**
     * which scene these targets are part of
     */
    final private SceneNode scene;
    /**
     * list of targets
     */
    final private ArrayList<Target> list;
    // *************************************************************************
    // constructors

    /**
     * Instantiate an empty list for the specified scene.
     *
     * @param scene which will contain the targets (not null)
     */
    public Targets(SceneNode scene) {
        assert scene != null;
        this.scene = scene;
        list = new ArrayList<>();
    }
    // *************************************************************************
    // new methods exposed

    /**
     * Create a target and add it to the list.
     *
     * @param location world location of the target (not null)
     * @param unit the target's unit (not null)
     */
    public void add(Vector3f location, Spatial unit) {
        assert location != null;
        assert unit != null;

        Target target = new Target(location, unit);
        list.add(target);
    }

    /**
     * Exclude a specified unit from the list.
     *
     * @param unit which unit to exclude (not null)
     */
    public void exclude(Spatial unit) {
        assert unit != null;

        for (Target target : list) {
            if (target.getUnit() == unit) {
                target.exclude();
            }
        }
    }

    /**
     * Score each target according its distance from a specified location.
     *
     * @param origin world location from which to measure distances (not null)
     * @param minRange (in meters, &ge;0)
     */
    public void scoreNearest(Vector3f origin, float minRange) {
        assert origin != null;

        for (Target target : list) {
            Vector3f targetLocation = target.getWorldLocation();
            float distance = MyVector3f.distanceFrom(targetLocation, origin);
            distance *= scene.getScaleFactor();
            if (distance < minRange) {
                distance = minRange;
            }
            target.setScore(-distance);
        }
    }

    /**
     * Select the target with the highest score.
     *
     * @return reference to a pre-existing target, or null
     */
    public Target select() {
        Target result = null;
        float bestScore = Target.excludedScore;
        for (Target target : list) {
            float score = target.getScore();
            if (score > bestScore) {
                bestScore = score;
                result = target;
            }
        }
        return result;
    }
}